
#define	NMN_ASSERTS_ON 1
#define NMN_ASSERTS_ALL 1

#include <iostream>
#include <needs_more_ninja/preprocessor/unused.hpp>
#include <needs_more_ninja/template/singleton/singleton.hpp>
#include <needs_more_ninja/template/singleton/singleton_proxy.hpp>
#include <needs_more_ninja/template/hashed_string.hpp>
#include <needs_more_ninja/template/casts.hpp>
#include <needs_more_ninja/template/math/math.hpp>
#include <needs_more_ninja/template/log/logger.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <functional>

class global : public nmn::singleton<global>
{
public:

	~global( )
	{
		nmn::output_message( "global deconstructor" );
	}

	void f( int i )
	{
		nmn::output_message( "output: %1%", i );
	}
};

class child : public global
{
};

int main( int argc, char** argv )
{
	NMN_UNUSED( argc );
	NMN_UNUSED( argv );

	nmn::logger log( "test_nmn_log.txt" );

	global::create_singleton<child>( );
	NMN_ASSERT( global::is_singleton_valid( ) );
	NMN_ASSERT( child::is_singleton_valid( ) );
	NMN_ASSERT(nmn::singleton<global>::is_singleton_valid( ) );
	NMN_ASSERT( global::get_singleton( ) == child::get_singleton( ) );

	global::get_singleton( )->f( 12 );
	nmn::singleton_proxy<global> global_proxy;
	((global &)global_proxy).f( 24 );

	boost::function<void ( int i )> f( boost::bind( &global::f, nmn::singleton_proxy<global>( ), _1 ) );
	f( 36 );

	global::destroy_singleton( );

	nmn::hashed_string test( "hashing_test" );
	boost::hash< std::string >	hasher;

	NMN_ASSERT( test.hash( ) == hasher( test.str( ) ) );

	nmn::hashed_string lazy_equality_a( "lazy_a" );
	nmn::hashed_string lazy_equality_b( "lazy_b" );
	nmn::basic_hashed_string< std::string, nmn::detail::use_strict_equality > strict_equality_a( "strict_a" );
	nmn::basic_hashed_string< std::string, nmn::detail::use_strict_equality > strict_equality_b( "strict_b" );

	log(	nmn::create_string(	"%1% %2% %3% %4%",
								( lazy_equality_a == lazy_equality_b ),
								( lazy_equality_a == strict_equality_a ),
								( strict_equality_b == lazy_equality_b ),
								( strict_equality_a == strict_equality_b ) ) );

	log( nmn::create_string( "%1% %2% %3%", test.hash( ), hasher( test.str( ) ), test ) );

	nmn::math::vector< float, 2 > v1( 1.1f, 2.2f );
	nmn::math::vector< float, 2 > v2( 3.3f, 4.4f );
	nmn::math::vector< float, 2 > v3 = v1 + v2;
	log( nmn::create_string( "%1% + %2% = %3%", v1, v2, v3 ) );

	v3 = v1 - v2;
	log( nmn::create_string( "%1% - %2% = %3%", v1, v2, v3 ) );

	v3 = v1 * v2;
	log( nmn::create_string( "%1% * %2% = %3%", v1, v2, v3 ) );

	float s1 = 5.5f;
	v3 = v1 * s1;
	log( nmn::create_string( "%1% * %2% = %3%", v1, s1, v3 ) );
	
	v3 = s1 * v1;
	log( nmn::create_string( "%1% * %2% = %3%", s1, v1, v3 ) );

	v3 = v1 / s1;
	log( nmn::create_string( "%1% / %2% = %3%", v1, s1, v3 ) );

	log( nmn::create_string( "%1% == %2% = %3%", v1, v1, v1 == v1 ) );
	log( nmn::create_string( "%1% != %2% = %3%", v1, v1, v1 != v1 ) );

	nmn::math::vector< bool, 3 > bvec3( true, false, true );
	log( nmn::create_string( "%1% %2% %3%", bvec3, bvec3.all( ), bvec3.any( ) ) );

	nmn::math::vector< bool, 3 > bvec3_2( false, true, false );

	std::swap( bvec3, bvec3_2 );
	log( nmn::create_string( "%1% %2% %3%", bvec3, bvec3.all( ), bvec3.any( ) ) );

	nmn::math::quaternion<float> q1( 0, 0, 0, 1 );
	log( nmn::create_string( "%1%", q1 ) );

	nmn::math::square_matrix< float, 2 > m2_0( nmn::math::vector< float, 2 >( 1.0f, 2.0f ), nmn::math::vector< float, 2 >( 3.0f, 4.0f ) );
	log( nmn::create_string( "%1%", m2_0 ) );

	nmn::math::square_matrix< float, 2 > m2_1( nmn::math::vector< float, 2 >( 5.0f, 6.0f ), nmn::math::vector< float, 2 >( 7.0f, 8.0f ) );
	log( nmn::create_string( "%1% * %2% = %3%", m2_0, m2_1, m2_0 * m2_1 ) );
	log( nmn::create_string( "%1% * %2% = %3%", m2_1, m2_0, m2_1 * m2_0 ) );
	log( nmn::create_string( "%1% * %2% = %3%", m2_0, v1, m2_0 * v1 ) );

	std::cin.get( );
	return 0;
}
